﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.Drawing;
using log4net;

namespace Entangle
{
    /// <summary>
    /// Interaction logic for EntangleMain.xaml
    /// </summary>
    public partial class EntangleMain : Window
    {
        private NotifyIcon ni;
        private string ni_text = String.Empty;
        private ContextMenuStrip cMenu;
        private RClickWindow rwin;

        private Dictionary<PartnerStates, Icon> statesIcons;

        RequestServiceHost rservice;
        System.Threading.Thread thRservice;

        ActivityMonitor monitor;
        Entangled entangled;

        User user;
        
        private static readonly ILog log = LogManager.GetLogger(typeof(EntangleMain));

        public EntangleMain()
        {
            this.Closing += new System.ComponentModel.CancelEventHandler(EntangleMain_Closing);
            this.Initialized += new EventHandler(EntangleMain_Initialized);

            statesIcons = new Dictionary<PartnerStates, System.Drawing.Icon>();
            statesIcons.Add(PartnerStates.Active, new Icon(@".\Resources\icons\1532_Flag_Green.ico"));
            statesIcons.Add(PartnerStates.Busy, new Icon(@".\Resources\icons\1532_Flag_Orange.ico"));
            statesIcons.Add(PartnerStates.Idle, new Icon(@".\Resources\icons\1532_Flag_Yellow.ico"));
            statesIcons.Add(PartnerStates.Offline, new Icon(@".\Resources\icons\1532_Flag_Red.ico"));
            statesIcons.Add(PartnerStates.Unknown, new Icon(@".\Resources\icons\1532_Flag_Grey.ico"));

            InitializeComponent();
        }

        void EntangleMain_Initialized(object sender, EventArgs e)
        {
            if (Configuration.SynchStatus == SynchStatus.Unknown)
            {
                Pair pairWnd = new Pair();
                if (pairWnd.ShowDialog() == false)
                    Close();
            }
            if (Configuration.SynchStatus == SynchStatus.UserIDObtained)
            {
                bool repeat = true;
                do
                {
                    if (!Cryptography.Instance.LoadPartnerPublicKey())
                    {
                        MessageBoxResult result = System.Windows.MessageBox.Show("Nie można pozyskać informacji o partnerze z serwera. Czy chcesz ponowić próbę?", "Błąd ładowania klucza", MessageBoxButton.YesNoCancel, MessageBoxImage.Information);
                        switch (result)
                        {
                            case MessageBoxResult.Yes:
                                break;
                            case MessageBoxResult.No:
                                repeat = false;
                                break;
                            case MessageBoxResult.Cancel:
                                Close();
                                return;
                        }
                    }
                    else
                    {
                        Configuration.SynchStatus = SynchStatus.Synched;
                        repeat = false;
                    }
                } while (repeat);
            }

            entangled = Entangled.Instance;
            entangled.PartnerStateChange += new EventHandler<PartnerStateChangeEventArgs>(entangled_PartnerStateChange);
            user = new User();

            StartRequestService();
            StartActivityMonitor();
            RunNotifyer();
        }

        private void SetNotifyIconStatus(PartnerState state)
        {
            ni.Icon = statesIcons[state.State];
            ni_text = state.Message;

            UpdateTooltip();
        }

        private void UpdateTooltip()
        {
            ni.Text = String.Format("{0} [{1} min]", ni_text, entangled.State.Time.TotalMinutes);
        }

        void entangled_PartnerStateChange(object sender, PartnerStateChangeEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new Action(() => SetNotifyIconStatus(e.State)));
        }

        private void StartActivityMonitor()
        {
            if (monitor != null)
            {
                if (monitor.Enabled)
                {
                    log.Info("ActivityMonitor is already running.");
                }
                else
                {
                    monitor.Enable();
                }
            }
            else
            {
                monitor = new ActivityMonitor(Properties.Settings.Default.UserIdleTresholdMin * 60 * 1000);
                monitor.UserActiveEvent += new EventHandler(monitor_UserActiveEvent);
                monitor.UserIdleEvent += new EventHandler(monitor_UserIdleEvent);
                monitor.Enable();
            }
        }

        private void StartRequestService()
        {
            if (Configuration.SynchStatus == SynchStatus.Synched)
            {
                if (rservice != null)
                {
                    if (rservice.isRunning)
                    {
                        log.Info("RequestServiceHost is already running.");
                        return;
                    }
                }
                rservice = new RequestServiceHost();
                thRservice = new System.Threading.Thread(rservice.Start);
                thRservice.IsBackground = true;
                thRservice.Start();

                int loops = 0;
                int msToSleep = 200;
                while (!rservice.isRunning)
                {
                    System.Threading.Thread.Sleep(msToSleep);
                    if ((++loops * msToSleep / 1000) > Properties.Settings.Default.MaxServiceStartupTimeSec)
                        throw new Exception("RequestService host didn't start in time!");
                }
            }
            else
            {
                log.Info("RequestServiceHost startup aborted because users are not fully synched.");
            }
        }


        void EntangleMain_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (rservice != null)
                if (rservice.isRunning)
                    rservice.Stop();

            if (thRservice != null)
                if (thRservice.IsAlive)
                    thRservice.Join();

            if (ni != null)
            {
                ni.Visible = false;
                ni.Dispose();
            }
        }

        void RunNotifyer()
        {
            ni = new NotifyIcon();
            ni.Text = "Status nieznany...";
            ni.Icon = statesIcons[PartnerStates.Unknown];

            // Context menu

            cMenu = new ContextMenuStrip();

            // Debug
            ToolStripMenuItem tsiDebug = new ToolStripMenuItem("Debug");
            ToolStripMenuItem tsiMessageCraft = new ToolStripMenuItem("Message crafter");
            tsiMessageCraft.Click += new EventHandler(tsiMessageCraft_Click);
            ToolStripMenuItem tsiServCon = new ToolStripMenuItem("Server Connector tester");
            tsiServCon.Click += new EventHandler(tsiServCon_Click);
            ToolStripMenuItem tsiCryptTest = new ToolStripMenuItem("Cryptographic tester");
            tsiCryptTest.Click += new EventHandler(tsiCryptTest_Click);

            tsiDebug.DropDownItems.Add(tsiMessageCraft);
            tsiDebug.DropDownItems.Add(tsiServCon);
            tsiDebug.DropDownItems.Add(tsiCryptTest);

            cMenu.Items.Add(tsiDebug);

            // States
            ToolStripMenuItem states = new ToolStripMenuItem("Stan");

            ToolStripMenuItem tsiActive = new ToolStripMenuItem("Dostępny");
            tsiActive.Click += new EventHandler(tsiActive_Click);
            ToolStripMenuItem tsiBusy = new ToolStripMenuItem("Zajęty");
            tsiBusy.Click += new EventHandler(tsiBusy_Click);

            states.DropDownItems.Add(tsiActive);
            states.DropDownItems.Add(tsiBusy);

            cMenu.Items.Add(states);
            // ---
            ToolStripLabel statusLabel = new ToolStripLabel("Status:");
            cMenu.Items.Add(statusLabel);
            ToolStripTextBox statusBox = new ToolStripTextBox();
            statusBox.Text = user.Message;
            statusBox.BorderStyle = BorderStyle.FixedSingle;
            statusBox.KeyDown += new System.Windows.Forms.KeyEventHandler(statusBox_KeyDown);
            statusBox.LostFocus += new EventHandler(statusBox_LostFocus);
            cMenu.Items.Add(statusBox);

            ToolStripMenuItem tsiExit = new ToolStripMenuItem("Zakończ");
            tsiExit.Click += new EventHandler(tsiExit_Click);
            cMenu.Items.Add(tsiExit);

            ni.ContextMenuStrip =  cMenu;
            // ---

            ni.Visible = true;
        }

        void tsiCryptTest_Click(object sender, EventArgs e)
        {
            try
            {
                new Entangle.Resources.Windows.Debug.CryptTest().Show();
            }
            catch (Exception ex)
            {
                log.Error("Error opening crypt tester.", ex);
            }
        }

        void tsiServCon_Click(object sender, EventArgs e)
        {
            try
            {
                new SConnectorTest().Show();
            }
            catch (Exception ex)
            {
                log.Error("Error opening server connector tester.", ex);
            }
        }

        void tsiMessageCraft_Click(object sender, EventArgs e)
        {
            try
            {
                new MessageCrafter().Show();
            }
            catch (Exception ex)
            {
                log.Error("Error opening message crafter.", ex);
            }
        }

        void statusBox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                e.SuppressKeyPress = true;
                ((ToolStripTextBox)sender).GetCurrentParent().Hide();
            }
        }

        void tsiExit_Click(object sender, EventArgs e)
        {
            if (Configuration.AskOnExit)
            {
                Entangle.Resources.Windows.ExitDialog eDialog = new Resources.Windows.ExitDialog();
                if ((bool)eDialog.ShowDialog())
                    Close();
            }
            else
            {
                Close();
            }
        }

        void statusBox_LostFocus(object sender, EventArgs e)
        {
            user.Message = ((ToolStripTextBox)sender).TextBox.Text;
        }

        #region Context Menu Items Event Handlers
        void tsiBusy_Click(object sender, EventArgs e)
        {
            user.State = PartnerStates.Busy;
        }

        void tsiActive_Click(object sender, EventArgs e)
        {
            user.State = PartnerStates.Active;
        }
        #endregion

        void monitor_UserIdleEvent(object sender, EventArgs e)
        {
            if (Configuration.SynchStatus != SynchStatus.Synched)
            {
                log.Debug("Skiping status update because useres are not fully synched.");
            }
            else
            {
                entangled.Notify(new PartnerState(PartnerStates.Idle, monitor.Idle, String.Empty));
            }
        }

        void monitor_UserActiveEvent(object sender, EventArgs e)
        {
            if (Configuration.SynchStatus != SynchStatus.Synched)
            {
                log.Debug("Skiping status update because useres are not fully synched.");
            }
            else
            {
                entangled.Notify(new PartnerState(PartnerStates.Active, TimeSpan.Zero, String.Empty));
            }
        }

        void rwin_Closed(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
